<template>
	<view class="e-collapse-item">
		<template v-if="$slots.cell">
			<view @tap="clickHandler">
				<slot name="cell" :expanded="expanded">
				
				</slot>
			</view>
		</template>
		<e-cell v-else :title="props.title" :value="props.value" :label="props.label" :icon="props.icon"
			:isLink="props.isLink" :clickable="props.clickable" :border="parentData.border && showBorder"
			@click="clickHandler" :arrowDirection="expanded ? 'up' : 'down'" :disabled="props.disabled">
			<!-- #ifndef MP-WEIXIN -->
			<!-- 微信小程序不支持，因为微信中不支持 <slot name="title" slot="title" />的写法 -->
			<template slot="title">
				<slot name="title"></slot>
			</template>
			<template slot="icon">
				<slot name="icon"></slot>
			</template>
			<template slot="value">
				<slot name="value"></slot>
			</template>
			<template slot="right-icon">
				<slot name="right-icon"></slot>
			</template>
			<!-- #endif -->
		</e-cell>
		<view class="e-collapse-item__content" :animation="animationData" >
			<view class="e-collapse-item__content__text content-class" :id="elId" ref="collapseItemRef">
				<slot />
			</view>
		</view>
		<e-line v-if="parentData.border"></e-line>
	</view>
</template>
<script lang="ts">
	import {
		defineComponent
	} from 'vue'
	import mpMixin from '../../libs/mixin/mpMixin'
	/**
	 * collapseItem 折叠面板Item
	 * @description 通过折叠面板收纳内容区域（搭配e-collapse使用）
	 * @tutorial https://www.uviewui.com/components/collapse.html
	 * @property {String}			title 		标题
	 * @property {String}			value 		标题右侧内容
	 * @property {String}			label 		标题下方的描述信息
	 * @property {Boolean}			disbled 	是否禁用折叠面板 ( 默认 false )
	 * @property {Boolean}			isLink 		是否展示右侧箭头并开启点击反馈 ( 默认 true )
	 * @property {Boolean}			clickable	是否开启点击反馈 ( 默认 true )
	 * @property {Boolean}			border		是否显示内边框 ( 默认 true )
	 * @property {String}			align		标题的对齐方式 ( 默认 'left' )
	 * @property {String | Number}	name		唯一标识符
	 * @property {String}			icon		标题左侧图片，可为绝对路径的图片或内置图标
	 * @event {Function}			change 			某个item被打开或者收起时触发
	 * @example <e-collapse-item :title="item.head" v-for="(item, index) in itemList" :key="index">{{item.body}}</e-collapse-item>
	 */
	export default defineComponent({
		name: "e-collapse-item",
		mixins: [mpMixin]
	});
</script>
<script setup lang="ts">
	import {
		watch,
		ref,
		reactive,
		onMounted,
		nextTick,
		inject,
		toRefs,
		onUnmounted,
		getCurrentInstance
	} from 'vue'
	import {
		collapseItemProps
	} from './props'
	import {
		useDefaultProps,
		useNamespace
	} from '../../libs/hooks'
	import componentsProps, {
		type DefaultProps
	} from "../../libs/config/componentsProps";
	import {
		isArray,
		nanoid,
		getRect,
		getNvueRect,
		type rectSize
	} from "../../libs/utils";
	import {
		throwError
	} from '../../libs/utils/_utils'
	import {
		collapseContextKey
	} from '../../libs/tokens'



	const {
		collapseItem: collapseItemDefaultProps
	} = toRefs(componentsProps);
	
	const ctx = getCurrentInstance()

	const _props = defineProps(collapseItemProps)
	const props = useDefaultProps < DefaultProps['collapseItem'] > (_props, collapseItemDefaultProps);

	const collapseContext = inject(collapseContextKey)
	if (!collapseContext) throwError('ECollapseItem', 'e-collapse-item需要结合e-collapse组件使用')

	const ns = useNamespace('collapse-item')
	// 用于获取dom信息
	const elId = ref(nanoid(21,true))
	const collapseItemRef = ref(null)
	
	const animationData = ref({})
	const expanded = ref(false)
	const showBorder = ref(false)
	const parentData = reactive({
		accordion: false,
		border: false
	})
	let [animating, timer]: [boolean, undefined | number] = [false, undefined]
	watch(
		() => expanded.value,
		(n: boolean) => {
			clearTimeout(timer)
			timer = undefined
			// 这里根据expanded的值来进行一定的延时，是为了cell的下划线更好的显示效果
			timer = setTimeout(
				() => {
					showBorder.value = n
				},
				n ? 10 : 290
			)
		}
	)
	// 异步获取内容，或者动态修改了内容时，需要重新初始化
	const init = () => {
		updateParentData()
		if (collapseContext.props.accordion) {
			if (isArray(collapseContext.props.value)) {
				throwError('ECollapseItem', '手风琴模式下，e-collapse组件的value参数不能为数组')
			}
			collapseContext.props.value ?? (expanded.value = props.value.name === collapseContext.props.value)
		} else {
			if (isArray(collapseContext.props.value)) {
				expanded.value = (collapseContext.props.value || []).some(item => item === props.value.name)
			} else {
				throwError('ECollapseItem', '非手风琴模式下，e-collapse组件的value参数必须为数组')
			}

		}
		// 设置组件的展开或收起状态
		nextTick().then(setContentAnimate)
	}
	const setContentAnimate = async () => {
		// 每次面板打开或者收起时，都查询元素尺寸
		// 好处是，父组件从服务端获取内容后，变更折叠面板后可以获得最新的高度
		const rect = await queryRect()
		const height = expanded.value ? rect.height! : 0
		animating = true

		const animation = uni.createAnimation({
			timingFunction: 'ease-in-out'
		})
		animation
			.height(height)
			.step({
				duration: props.value.duration
			})
			.step()
		// 导出动画数据给面板的animationData值
		animationData.value = animation.export()
		// 标识动画结束
		setTimeout(() => {
			animating = false
		}, props.value.duration)
	}
	const getParentData = () => {
		Object.keys(parentData).map(key => {
			parentData[key] = collapseContext[key]
		})
	}
	const updateParentData = () => {
		getParentData()
	}
	// 点击collapsehead头部
	const clickHandler = () => {
		if (props.value.disabled && animating) return
		// 设置本组件为相反的状态
		collapseContext?.onChange?.({
			expanded: expanded.value,
			name: props.value.name,
			uid: elId.value
		})
	}
	// 查询内容高度
	const queryRect = (): Promise < rectSize > => {
		// #ifndef APP-NVUE
		return new Promise(resolve => {
			getRect(ctx,`#${elId.value}`).then(size => {
				resolve(size)
			})
			
		})
		// #endif
		
		// #ifdef APP-NVUE
		return new Promise(resolve => {
			getNvueRect(collapseItemRef.value).then(size => {
				resolve(size)
			})
		})
		// #endif
		
	}
	// 初始化数据
	collapseContext?.addField({
		uid: elId.value,
		states: reactive({
			expanded,
			name: props.value.name
		}),
		init,
		setContentAnimate
	})
	onMounted(init)
	onUnmounted(() => {
		collapseContext.removeField(elId.value)
	})
</script>

<style lang="scss" scoped>
	@import "../../libs/theme/collapse-item.scss";
</style>
